#![no_std]
#![feature(vec_into_raw_parts)]
#![feature(get_mut_unchecked)]
#![feature(untagged_unions)]
#![feature(llvm_asm)]
#![feature(naked_functions)]
#![feature(proc_macro_hygiene)]
#![allow(unused_variables)]
#![allow(unused_must_use)]
#![allow(dead_code)]
#![allow(deprecated)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]

cfg_if! {
    if #[cfg(any(feature="std", not(windows)))] {
        extern crate std;
        pub mod elf;
        pub mod text;
    }
}

pub extern crate iced_x86;
#[macro_use] extern crate alloc;
#[macro_use] extern crate cfg_if;
#[macro_use] extern crate derive_more;

pub mod reg;
pub mod err;
pub mod mem;
pub mod util;
pub mod strutil;

#[cfg(all(feature="std", feature="csutil"))]
pub mod csutil;
#[cfg(all(feature="std", windows))]
pub mod pe;

pub use reg::*;
pub use err::*;
pub use mem::*;
pub use util::*;
pub use strutil::*;

cfg_if! {
    if #[cfg(windows)] {
        pub mod win;
        pub use crate::win::*;
    } else {
        pub mod nix;
        pub use crate::nix::*;
    }
}

use alloc::sync::Arc;
use alloc::vec::Vec;
use alloc::boxed::Box;
use alloc::string::*;

use serde::{Deserialize, Serialize};
#[cfg(windows)]
use winapi::{
    shared::minwindef::*,
    um::{
        processthreadsapi::CreateThread,
        winnt::*,
        winbase::*,
        minwinbase::LPTHREAD_START_ROUTINE,
    }
};

cfg_if! {
    if #[cfg(target_arch = "x86")] {
        pub const HKIT_ARCH: &str = "x86";
        pub type Registers = X86Regs;
    } else if #[cfg(target_arch = "x86_64")] {
        pub const HKIT_ARCH: &str = "x86_64";
        pub type Registers = X64Regs;
    } else if #[cfg(target_arch = "arm")] {
        pub const HKIT_ARCH: &str = "arm";
        pub type Registers = ArmRegs;
    } else if #[cfg(target_arch = "aarch64")] {
        pub const HKIT_ARCH: &str = "aarch64";
        pub type Registers = Arm64Regs;
    }
}

pub type Address = usize;

pub struct CommonModule {
    pub base: usize,
    pub size: usize,
}

pub trait HKitModule {
    fn comm(&self) -> &CommonModule;
    fn name(&self) -> Arc<str>;
    fn path(&self) -> Arc<str>;
}

#[derive(Serialize, Deserialize)]
pub struct SymbolInfo {
    pub module: Arc<str>,
    pub symbol: Arc<str>,
    pub offset: usize,
    pub mod_base: usize,
}

impl SymbolInfo {
    pub fn to_string(&self, addr: Address) -> String {
        if self.symbol.len() > 0 {
            if self.offset == 0 {
                format!("{}!{}", self.module, self.symbol)
            } else {
                format!("{}!{}+{:x}", self.module, self.symbol, self.offset)
            }
        } else if self.module.len() > 0 {
            if addr == self.mod_base {
                self.module.to_string()
            } else {
                format!("{}+{:x}", self.module, addr - self.mod_base)
            }
        } else { format!("{:x}", addr) }
    }
}

#[cfg(windows)]
pub use win::symbol::undecorate_symbol as undecorate_symbol_win;

#[cfg(feature="std")]
pub fn undecorate_symbol(sym: &str) -> Option<String> {
    use cpp_demangle::{Symbol, DemangleOptions};
    Symbol::new(sym).ok().and_then(|s|
        s.demangle(&DemangleOptions::new().no_params().no_return_type()).ok()
    )
}
